﻿Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization
Imports Microsoft.Reporting.WinForms

Public Class DynamicAddCol
    'https://blog.csdn.net/weixin_30394633/article/details/98573176
    '不懂请查阅
    Public Sub New(rptViewer1 As ReportViewer)
        reportViewer1 = rptViewer1
    End Sub



    Dim reportViewer1 As ReportViewer
    ''' <summary>
    ''' 主流程
    ''' </summary>
    Public Sub ModifyReportFile(dataSource As DataTable, colNameList As List(Of String))


        '修改rdlc文件
        Dim xmlDoc = ModifyRdlc(colNameList)

        '将修改后的rdlc文档序列化到内存流中
        Dim stream = GetRdlcStream(xmlDoc)

        '加载报表定义
        reportViewer1.LocalReport.LoadReportDefinition(stream)
        'rvDemo.LocalReport.ReportPath = "FirstRdlc.rdlc"
    End Sub

    ''' <summary>
    ''' 修改RDLC文件 (为了动态生成N 列)
    ''' </summary>
    ''' <returns></returns>
    Private Function ModifyRdlc(colNameList As List(Of String)) As XmlDocument

        Dim xmlDoc = New XmlDocument()

        xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "Report1.rdlc")

        For index = 0 To colNameList.Count - 1

            '添加Field节点
            Dim fileds = xmlDoc.GetElementsByTagName("Fields")

            Dim filedNode = fileds.Item(0).FirstChild.CloneNode(True)

            filedNode.Attributes("Name").Value = colNameList(index)

            filedNode.FirstChild.InnerText = colNameList(index)
            fileds.Item(0).AppendChild(filedNode)


            '添加TablixColumn

            Dim tablixColumns = xmlDoc.GetElementsByTagName("TablixColumns")
            Dim tablixColumn = tablixColumns.Item(0).FirstChild
            Dim newtablixColumn = tablixColumn.CloneNode(True)
            tablixColumns.Item(0).AppendChild(newtablixColumn)

            'TablixMember
            Dim tablixMembers = xmlDoc.GetElementsByTagName("TablixColumnHierarchy")

            Dim tablixMember = tablixMembers.Item(0).FirstChild.FirstChild
            Dim newTablixMember = tablixMember.CloneNode(True)
            tablixMembers.Item(0).FirstChild.AppendChild(newTablixMember)

            Dim tablixRows = xmlDoc.GetElementsByTagName("TablixRows")

            'TablixRows1
            Dim tablixRowsRowCells1 = tablixRows.Item(0).FirstChild.ChildNodes(1)
            Dim tablixRowCell1 = tablixRowsRowCells1.FirstChild
            Dim newtablixRowCell1 = tablixRowCell1.CloneNode(True)
            Dim textBox1 = newtablixRowCell1.FirstChild.ChildNodes(0)

            textBox1.Attributes("Name").Value = "GPA1"

            ' VB lamdba 一行写完根本不可能.
            Dim paragraphs = textBox1.ChildNodes.Cast(Of XmlNode)().Where(Function(item)
                                                                              Return item.Name = "Paragraphs"
                                                                          End Function).FirstOrDefault()

            paragraphs.FirstChild.FirstChild.FirstChild.FirstChild.InnerText = "GPA"

            Dim defaultName1 = textBox1.ChildNodes.Cast(Of XmlNode)().Where(Function(item)
                                                                                Return item.Name = "rd:DefaultName"
                                                                            End Function).FirstOrDefault().InnerText = "GPA1"

            tablixRowsRowCells1.AppendChild(newtablixRowCell1)

            'TablixRows2
            Dim tablixRowsRowCells2 = tablixRows.Item(0).ChildNodes(1).ChildNodes(1)
            Dim tablixRowCell2 = tablixRowsRowCells2.FirstChild
            Dim newtablixRowCell2 = tablixRowCell2.CloneNode(True)
            Dim textBox2 = newtablixRowCell2.FirstChild.ChildNodes(0)
            textBox2.Attributes("Name").Value = colNameList(index)

            Dim paragraphs2 = textBox2.ChildNodes.Cast(Of XmlNode)().Where(Function(item)
                                                                               Return item.Name = "Paragraphs"
                                                                           End Function).FirstOrDefault()

            paragraphs2.FirstChild.FirstChild.FirstChild.FirstChild.InnerText = "=Fields!GPA.Value"
            Dim defaultName2 = textBox2.ChildNodes.Cast(Of XmlNode)().Where(Function(item)
                                                                                Return item.Name = "rd:DefaultName"
                                                                            End Function).FirstOrDefault().InnerText = colNameList(index)

            tablixRowsRowCells2.AppendChild(newtablixRowCell2)


        Next



        xmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "Report1.rdlc")
        Return xmlDoc

    End Function


    Private Function GetRdlcStream(xmlDoc As XmlDocument) As Stream
        Dim ms As Stream = New MemoryStream()
        Dim serializer = New XmlSerializer(xmlDoc.GetType())
        serializer.Serialize(ms, xmlDoc)
        ms.Position = 0
        Return ms
    End Function

    Private Sub ModifyXSD()
        Dim xmlDoc = New XmlDocument()
        xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "Students.xsd")

        Dim nodeList = xmlDoc.GetElementsByTagName("xs:sequence")
        Dim node = nodeList.Item(0).FirstChild.CloneNode(True)
        node.Attributes("name").Value = "GPA"
        node.Attributes("msprop:Generator_ColumnVarNameInTable").Value = "columnGPA"
        node.Attributes("msprop:Generator_ColumnPropNameInRow").Value = "GPA"
        node.Attributes("msprop:Generator_ColumnPropNameInTable").Value = "GPAColumn"
        node.Attributes("msprop:Generator_UserColumnName").Value = "GPA"
        nodeList.Item(0).AppendChild(node)

        xmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "Students1.xsd")
    End Sub



    Private Function GetDataSource() As DataTable
        '伪造一个数据源
        Dim dt = New DataTable()

        dt.Columns.Add("RecId")
        dt.Columns.Add("Name")
        dt.Columns.Add("Age")
        dt.Columns.Add("Class")
        dt.Columns.Add("Scores")
        dt.Columns.Add("GPA")


        Dim dr = dt.NewRow()
        dr("RecId") = "1"
        dr("Name") = "小明"
        dr("Age") = "26"
        dr("Class") = "1年级"
        dr("Scores") = "90"
        dr("GPA") = "4.0"

        dt.Rows.Add(dr)
        Return dt
    End Function

End Class
